#ifndef ODBC_PREPARED_STAT_EXEC_POLICY_HPP
#define ODBC_PREPARED_STAT_EXEC_POLICY_HPP

#include "odbc/odbc_error.hpp"

namespace odbc
{


// TODO: Document
class prepared_stat_exec_policy
{
public:
	static void prepare_statement( SQLHANDLE stat_handle, const std::string& stat_str)
	{
		SQLRETURN retCode = SQLPrepare(
			stat_handle,
			(SQLCHAR*)stat_str.c_str(),
			SQLINTEGER( stat_str.size()));
		throw_if_stat_failed( retCode, stat_handle);
	}

	static void execute_statement( SQLHANDLE stat_h, const std::string&)
	{
		SQLCloseCursor( stat_h);
		SQLRETURN retCode = SQLExecute( stat_h);
		throw_if_stat_failed( retCode, stat_h);
	}

	template< class Buffer>
	static void bind_parameter( Buffer& buff, SQLHANDLE stat_handle, SQLUSMALLINT position, SQLSMALLINT direction)
	{
		SQLRETURN ret_code = SQLBindParameter( 
			stat_handle, position, direction, 
			(SQLSMALLINT)Buffer::odbc_type_id, 
			(SQLSMALLINT)Buffer::sql_type_id,
			(SQLINTEGER)buff.size(),
			0, 
			(SQLPOINTER)buff.buffer_addr(),
			(SQLINTEGER)buff.size(),
			(SQLINTEGER*)buff.length_indicator_ptr());
		throw_if_stat_failed( ret_code , stat_handle);
	}

	template< class Buffer>
	static boost::any fetch_parameter( Buffer& buff, SQLHANDLE , SQLUSMALLINT )
	{
		return buff.contains_null() ? boost::any() : boost::any( buff.value());
	}

	template< class Buffer>
	static void bind_column( Buffer& buff, SQLHANDLE stat_handle, SQLUSMALLINT position)
	{
		SQLRETURN ret_code = SQLBindCol( 
			stat_handle,
			position,
			(SQLSMALLINT)Buffer::odbc_type_id,
			(SQLPOINTER)buff.buffer_addr(),
			(SQLINTEGER)buff.size(),
			buff.length_indicator_ptr());
		throw_if_stat_failed( ret_code , stat_handle);
	}

	template< class Buffer>
	static boost::any fetch_column( Buffer& buff, SQLHANDLE , SQLUSMALLINT )
	{
		return buff.contains_null() ? boost::any() : boost::any( buff.value());
	}

};


} // namespace odbc

#endif // ODBC_PREPARED_STAT_EXEC_POLICY_HPP
